#include <sys/types.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <event.h>
#include <evmsg.h>
#include <assert.h>

struct session {
  char *id;

  void *subscription;

  TAILQ_ENTRY(session) next;
};

const char _sdp_pipo[] = 
"v=0\n"
"o=user1 53655765 2353687637 IN IP4 127.0.0.1\n"
"s=-\n"
"c=IN IP4 127.0.1.1\n"
"t=0 0\n"
"m=audio 6000 RTP/AVP 0\n"
"a=rtpmap:0 PCMU/8000\n";

static int _extract_sdp(const char *msg, size_t len, char **content,
  size_t *content_len) {
  void *start, *end;
  start = memchr(msg, '(', len);
  end = memrchr(msg, ')', len);
  assert(start != NULL && end != NULL);

  *content = start + 1;
  *content_len = end - start - 1;

  return (*content_len > 0);
}

static void _publish(const char *topic, const char *type,
  const char *fmt, ...) {
  struct evbuffer *buf;
  va_list ap;

  va_start(ap,fmt);

  buf = evbuffer_new();
  assert(buf != NULL);

  evbuffer_add_vprintf(buf, fmt, ap);

  evmsg_publish(topic, type, buf);

  evbuffer_free(buf);

  va_end(ap);
}

static void _session_listener(const char *channel,
  const char *type, const char *sender,
  struct evbuffer *buf, void *arg) {
  const char *evt = (const char *) EVBUFFER_DATA(buf);
  char *sdp;
  size_t sdp_len;
  struct session *s = arg;

/*  fprintf(stderr, "'%s' type(%s) sender(%s) payload(%.*s)\n",
    channel, type, sender, EVBUFFER_LENGTH(buf), evt); */

  /* incoming(sdp), sdp may be empty */
  if (strncmp("incoming", evt, 8) == 0) {
    _extract_sdp(evt, EVBUFFER_LENGTH(buf), &sdp, &sdp_len);

    if (sdp_len != 0)
      _publish(s->id, "signalling/command", "answer(%s)", _sdp_pipo);
    else
      _publish(s->id, "signalling/command", "offer(%s)", _sdp_pipo);
  }
  /* hangup */
  else if (strncmp("hangup", evt, 6) == 0) {
    fprintf(stderr, "'%s' remote hangup\n", s->id);
  }
  else {
    fprintf(stderr, "'%s' unknown event '%.*s'\n", s->id,
      EVBUFFER_LENGTH(buf), evt);
  }
}

/* new incoming sessions come from here */
static void _sessions_listener(const char *channel,
  const char *type, const char *sender,
  struct evbuffer *buf, void *arg) {
  struct session *s;

  s = calloc(1, sizeof *s);
  assert(s != NULL);

  asprintf(&s->id, "%.*s", EVBUFFER_LENGTH(buf), EVBUFFER_DATA(buf));

  s->subscription = evmsg_subscribe(s->id, "signalling/event", "sipua", _session_listener, s);
  assert(s->subscription != NULL);
}

int main(int argc, char **argv) {
  void *subscription;

  event_init();

  evmsg_open("127.0.0.1", 8888, 0);
  evmsg_set_auth("service", "service");

  subscription = evmsg_subscribe("/sessions", "signalling/incoming", "sipua",
    &_sessions_listener, NULL);
  assert(subscription != NULL);

  event_dispatch();

  return 0;
}
